﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace LPBToolsLib.NetSocket
{
    public delegate void SocketEventCallBack(object sender, Socket ClientSocket);

    public interface TCPServerInterface
    {
        string LocalIPAddress { get; set; }
        int LocalPort { get; set; }
        int OnlineCount { get; }
        string[] ClientEndPoints { get; }
        bool RemoveClient(TCPSerClientThread fClient);
        void OnRecDataEvent(object sender, Socket ClientSocket, ref byte[] RecData);
    }

    /// <summary>
    /// TCPServer模块
    /// 测试：2023-04-24
    /// 260个客户端运行正常。
    /// 注意：该模块CPU使用率不超过1%，但是前端过于频繁的运行信息显示会造成程序无响应
    /// </summary>
    public class TCPServerSocket: TCPServerInterface
    {
        /// <summary>
        /// 获取本机IP， 静态函数
        /// </summary>
        /// <returns></returns>
        public static IPAddress getIpAddress()
        {
            //获取本地的IP地址
            string AddressIP = string.Empty;
            IPAddress ip = null;
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    AddressIP = _IPAddress.ToString();
                    ip = _IPAddress;
                }
            }
            return ip;
        }

        public static IPAddress[] getIpAddressList()
        {
            //获取本地的IP地址
            List<IPAddress> IPList = new List<IPAddress>();
            UnicastIPAddressInformationCollection ip = null;
            NetworkInterface[] ni = NetworkInterface.GetAllNetworkInterfaces();
            for (int i = 0; i < ni.Length; i++)
            {
                ip = ni[i].GetIPProperties().UnicastAddresses;
                for (int j = 0; j < ip.Count; j++)
                    if (ip[j].Address.AddressFamily== AddressFamily.InterNetwork)
                        IPList.Add(ip[j].Address);
            }
            return IPList.ToArray();
        }

        #region 成员
        protected Socket fTCPServer { get; set; }
        protected Thread fListenThd { get; set; }
        protected bool iListenRun { get; set; }

        protected string fNetAddress = "127.0.0.1";
        protected int fNetPort = 9848;

        public int Backlog { get; set; }
        /// <summary>
        /// 客户端列表
        /// </summary>
        protected Dictionary<string, TCPSerClientThread> dTCPClients { get; set; }
        /// <summary>
        /// 线程锁
        /// </summary>
        private Mutex MutexClientsThd = new Mutex(false, "MutexClientsManger:" + Guid.NewGuid().ToString());

        public event SocketEventCallBack OnConnect = null;
        public event SocketEventCallBack OnDisconnect = null;
        public event SocketEventCallBack AfterDisconnect = null;
        public event SocketRecDataCallBack OnReceive = null;

        public Recorder_Error ErrorRecorder { get; set; } = null;
        public Recorder_RTxBytes RTxBytes { get; set; } = null;

        /// <summary>
        /// 监听地址
        /// </summary>
        public string LocalIPAddress
        {
            get
            {
                return fNetAddress;
            }
            set
            {
                fNetAddress = value;
            }
        }

        /// <summary>
        /// 监听端口
        /// </summary>
        public int LocalPort
        {
            get
            {
                return fNetPort;
            }
            set
            {
                fNetPort = value;
            }
        }
        /// <summary>
        /// 监听点信息
        /// </summary>
        public IPEndPoint LocalIPEndPoint
        {
            get
            {
                IPAddress fLocalIP;
                if ((IPAddress.TryParse(fNetAddress, out fLocalIP))
                    && (fNetPort > 0) && (fNetPort < 0x10000))
                {
                    IPEndPoint fIPEndPoint = new IPEndPoint(fLocalIP, fNetPort);
                    return fIPEndPoint;
                }
                else
                    return null;
            }
        }
        /// <summary>
        /// 服务器是否在运行
        /// </summary>
        public bool SerActive
        {
            get
            {
                if (fListenThd != null)
                    return fListenThd.IsAlive;
                else
                    return false;
            }
        }
        /// <summary>
        /// 当前连接到服务器的客户数量
        /// </summary>
        public int OnlineCount { get { return dTCPClients.Count; } }
        /// <summary>
        /// 连接到服务器的全部客户的IPEndPoint
        /// </summary>
        public string[] ClientEndPoints
        {
            get
            {
                MutexClientsThd.WaitOne();
                try
                {
                    string[] tTmp = new string[dTCPClients.Count];
                    dTCPClients.Keys.CopyTo(tTmp, 0);
                    return tTmp;
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
            }
        }
        #endregion

        #region 构建函数，守护线程

        public TCPServerSocket()
        {
            Backlog = 250;
            dTCPClients = new Dictionary<string, TCPSerClientThread>();
            ClientsManagerEnable = true;
        }
        /// <summary>
        /// 自动绑定当前系统所有IP地址
        /// </summary>
        /// <param name="fSerPort"></param>
        public TCPServerSocket(int fSerPort) : this()
        {
            fNetAddress = IPAddress.Any.ToString();
            fNetPort = fSerPort;
            try
            {
                fTCPServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                fTCPServer.Bind(new IPEndPoint(IPAddress.Any, fNetPort));
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
            }
        }
        /// <summary>
        /// 仅绑定指定IP地址
        /// </summary>
        /// <param name="fSerIPAddress"></param>
        /// <param name="fSerPort"></param>
        public TCPServerSocket(IPAddress fSerIPAddress, int fSerPort) : this()
        {
            fNetAddress = fSerIPAddress.ToString();
            fNetPort = fSerPort;
            try
            {
                fTCPServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                fTCPServer.Bind(new IPEndPoint(IPAddress.Parse(fNetAddress), fNetPort));
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
            }
        }
        #endregion

        public void StartListen()
        {
            try
            {
                if (Backlog > 0)
                    fTCPServer.Listen(Backlog);
                else
                    fTCPServer.Listen(250);

                iListenRun = true;
                fListenThd = new Thread(new ThreadStart(Listen));
                fListenThd.Name = "服务器监听线程";
                fListenThd.Start();
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
            }
        }
        /// <summary>
        /// 2022-12-25
        /// </summary>
        /// <param name="tSerEP"></param>
        public void StartListen(IPEndPoint tSerEP)
        {
            if ((tSerEP != null) && (fTCPServer == null))
            {
                fNetAddress = tSerEP.Address.ToString();
                fNetPort = tSerEP.Port;
                try
                {
                    fTCPServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    fTCPServer.Bind(tSerEP);
                }
                catch (Exception ex)
                {
                    if (ErrorRecorder != null)
                        ErrorRecorder.setRecord(ex);
                    else
                        throw ex;
                }
                StartListen();
            }
        }
        /// <summary>
        /// 停止监听
        /// </summary>
        public void StopListen()
        {
            try
            {
                iListenRun = false;
                fListenThd = null;
                fTCPServer?.Close();
                MutexClientsThd.WaitOne();
                try
                {
                    foreach (string sClientEP in dTCPClients.Keys)
                        dTCPClients[sClientEP].Stop();
                    dTCPClients.Clear();
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
                ClientsManagerEnable = false;
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
            }
        }
        /// <summary>
        /// 向指定的从机发送数据，从机必须已经连接
        /// </summary>
        /// <param name="fData"></param>
        /// <param name="fDestIPEndPoint"></param>
        /// <returns>已经发送的数据字节数</returns>
        public int SendBytes(byte[] fData, string fDestIPEndPoint)
        {
            MutexClientsThd.WaitOne();
            try
            {
                if (dTCPClients.ContainsKey(fDestIPEndPoint))
                {
                    RTxBytes?.setRecord(new Record_Byte("Rec(" + fDestIPEndPoint + ")", fData));
                    return dTCPClients[fDestIPEndPoint].SendBytes(fData);

                }
            }
            finally
            {
                MutexClientsThd.ReleaseMutex();
            }
            return 0;
        }

        public int SendBytes(byte[] fData, IPEndPoint fDestIPEndPoint)
        {
            return SendBytes(fData, fDestIPEndPoint.ToString());
        }

        #region 监听管理

        /// <summary>
        /// 移除某个客户端
        /// </summary>
        /// <param name="fClient"></param>
        public int AddClient(TCPSerClientThread fClient)
        {
            IPEndPoint tDestIPEndPoint = fClient.RemoteIP;
            if ((tDestIPEndPoint != null) &&
                (!dTCPClients.ContainsKey(tDestIPEndPoint.ToString())))
            {
                MutexClientsThd.WaitOne();
                try
                {
                    dTCPClients.Add(tDestIPEndPoint.ToString(), fClient);
                    return dTCPClients.Count;
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
            }
            return -1;
        }

        /// <summary>
        /// 移除某个客户端
        /// </summary>
        /// <param name="fClient"></param>
        public bool RemoveClient(TCPSerClientThread fClient)
        {
            IPEndPoint tDestIPEndPoint = fClient.RemoteIP;
            if ((tDestIPEndPoint != null) &&
                dTCPClients.ContainsKey(tDestIPEndPoint.ToString()))
            {
                MutexClientsThd.WaitOne();
                try
                {
                    dTCPClients.Remove(tDestIPEndPoint.ToString());
                    return true;
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
            }
            return false;
        }

        /// <summary>
        /// 监听线程
        /// </summary>
        protected void Listen()
        {
            while (iListenRun)
            {
                try
                {
                    Socket tClientSocket = fTCPServer.Accept();
                    if (tClientSocket != null)
                    {
                        TCPSerClientThread tClientThread = new TCPSerClientThread(this, tClientSocket);
                        tClientThread.OnDisconnect += OnDisconnect;
                        tClientThread.AfterDisconnect += AfterDisconnect;
                        tClientThread.OnResponRequest += FClientThread_OnResponRequest;
                        tClientThread.ErrorRecorder = ErrorRecorder;
                        AddClient(tClientThread);
                        OnConnect?.Invoke(this, tClientSocket);
                        tClientThread.Start();
                    }
                }
                catch (Exception ex)
                {
                    if (ErrorRecorder != null)
                        ErrorRecorder.setRecord(ex);
                    else
                        throw ex;
                    break;
                }

                Thread.Sleep(1);
            }
            StopListen();
        }

        private void FClientThread_OnResponRequest(object sender, Socket ClientSocket, ref byte[] RecData)
        {
            RTxBytes?.setRecord(new Record_Byte("Rec(" + ClientSocket.RemoteEndPoint.ToString() + ")", RecData));
        }
        #endregion

        public virtual void OnRecDataEvent(object sender, Socket ClientSocket, ref byte[] RecData)
        {
            RTxBytes?.setRecord(new Record_Byte("Rec("+ ClientSocket.RemoteEndPoint.ToString()+")", RecData));
            OnReceive?.Invoke(sender, ClientSocket, ref RecData);
        }

        #region 客户端列表维护

        /// <summary>
        /// 是否启动客户端列表维护
        /// </summary>
        private bool bCliMEnable { get; set; } = false;
        /// <summary>
        /// 是否启动客户端列表维护
        /// </summary>
        public bool ClientsManagerEnable
        {
            get { return bCliMEnable; }
            set
            {
                bCliMEnable = value;
                if (value)
                {
                    // 启动客户端在线监测线程
                    Thread THDClientOnLine = new Thread(ThdClientsManager);
                    THDClientOnLine.Start();
                }
                else
                    Thread.Sleep(1);
            }
        }

        /// <summary>
        /// 客户端在线超时，单位：s
        /// </summary>
        private int iCliSleepTimeOut = 60;
        /// <summary>
        /// 客户端在线超时，单位：s。最小时长3s
        /// </summary>
        public int ClientSleepTimeOut
        {
            get { return iCliSleepTimeOut; }
            set
            {
                if (value < 10)
                    iCliSleepTimeOut = 10;
                else
                    iCliSleepTimeOut = value;
            }
        }
        /// <summary>
        /// 监测客户是否在线
        /// </summary>
        private void ThdClientsManager()
        {
            while (bCliMEnable)
                try
                {
                    List<string> sTimeOutClientEPList = new List<string>();
                    if (dTCPClients.Count > 0)
                    {
                        foreach (KeyValuePair<string, TCPSerClientThread> item in dTCPClients)
                            // 判断客户端最后在线时间
                            if (((DateTime.Now - item.Value.LastAction).TotalSeconds > ClientSleepTimeOut)
                                || (!item.Value.Connected))
                                sTimeOutClientEPList.Add(item.Key);
                        // 发现超时，删除对象
                        if (sTimeOutClientEPList.Count > 0)
                            foreach (string sEP in sTimeOutClientEPList)
                            {
                                MutexClientsThd.WaitOne();
                                try
                                {
                                    if (dTCPClients.ContainsKey(sEP))
                                    {
                                        dTCPClients[sEP].Stop();
                                        dTCPClients.Remove(sEP);
                                    }
                                }
                                finally
                                {
                                    MutexClientsThd.ReleaseMutex();
                                }
                            }
                               
                    }
                }
                catch(Exception ex)
                {
                    ErrorRecorder?.setRecord(ex);
                }
                finally
                {
                    Thread.Sleep(10);
                }
        }
        #endregion
    }

    /// <summary>
    /// 用于服务器处理每个客户端的线程
    /// </summary>
    public class TCPSerClientThread 
    {
        public Socket tClientSocket { get; set; }
        protected Thread tClientThd { get; set; }
        protected TCPServerInterface tSerSocket { get; set; }

        public event SocketEventCallBack OnDisconnect = null;
        public event SocketEventCallBack AfterDisconnect = null;
        public event SocketRecDataCallBack OnResponRequest = null;
        public Recorder_Error ErrorRecorder { get; set; } = null;

        public object Tag { get; set; }

        public bool Connected { get { return (tClientSocket != null) && tClientSocket.Connected; } }

        public string RemoteAddress { get { return tClientSocket.RemoteEndPoint.ToString(); } }

        public IPEndPoint RemoteIP
        {
            get
            {
                if (tClientSocket != null)
                    return (IPEndPoint)tClientSocket.RemoteEndPoint;
                else
                    return null;
            }
        }

        public DateTime LastAction { get; set; }

        public TCPSerClientThread(TCPServerInterface fServerX, Socket fClientX)
        {
            LastAction = DateTime.Now;
            this.tSerSocket = fServerX;
            tClientSocket = fClientX;
        }

        /// <summary>
        /// 开始客户线程
        /// </summary>
        public void Start()
        {
            tClientThd = new Thread(new ThreadStart(StartThread));
            tClientThd.Name = "客户线程";
            tClientThd.Start();
        }
        bool thdRun { get; set; } = true;
        /// <summary>
        /// 停止客户线程
        /// </summary>
        public void Stop()
        {
            try
            {
                tClientSocket.Shutdown(SocketShutdown.Both);
                thdRun = false;
                Thread.Sleep(3);
                //tClientThd.Interrupt();
                tClientThd = null;
                tClientSocket.Close();
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
            }
        }

        private void StartThread()
        {
            byte[] buffer = new byte[1024];
            while (thdRun)
            {
                try
                {
                    int fRecCount = 0;
                    fRecCount = tClientSocket.Receive(buffer, SocketFlags.Peek);
                    //fRecCount = fClientSocket.Available;
                    if (fRecCount != 0)
                    {
                        this.LastAction = DateTime.Now;
                        if (tSerSocket != null)
                        {
                            byte[] fRecbuf = new byte[fRecCount];
                            tClientSocket.Receive(fRecbuf, SocketFlags.None);
                            tSerSocket?.OnRecDataEvent(this, tClientSocket, ref fRecbuf);
                            if ((fRecbuf != null) && (fRecbuf.Length > 0))
                            {
                                tClientSocket?.Send(fRecbuf, 0, fRecbuf.Length, SocketFlags.None);
                                if (OnResponRequest != null)
                                    OnResponRequest(this, tClientSocket, ref fRecbuf);
                            }
                        }
                    }
                    else
                    {
                        OnDisconnect?.Invoke(this, tClientSocket);  
                        tSerSocket?.RemoveClient(this);
                        AfterDisconnect?.Invoke(this, tClientSocket);
                        tClientSocket.Close();
                        break;
                    }
                }
                catch (Exception ex)
                {
                    ErrorRecorder?.setRecord(ex);
                    return;
                }
                Thread.Sleep(1);
            }
            tClientSocket.Close();
        }

        public int SendBytes(byte[] fSendData)
        {
            try
            {
                this.LastAction = DateTime.Now;
                if ((tClientSocket != null) && (tClientSocket.Connected))
                    return tClientSocket.Send(fSendData, 0, fSendData.Length, SocketFlags.None);
                else
                {
                    if (tSerSocket != null)
                        tSerSocket.RemoveClient(this);
                    AfterDisconnect?.Invoke(this, tClientSocket);
                }
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
            }
            return 0;
        }

        public int Poll()
        {
            this.LastAction = DateTime.Now;
            if (tClientSocket.Poll(-1, SelectMode.SelectRead))
            {
                byte[] buffer = new byte[1024];
                return tClientSocket.Receive(buffer, SocketFlags.Peek);
            }
            else
                return -1;
        }
    }
}
